home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 126-150 / disk_126 / suplib / dio.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  11KB  |  423 lines

  1.  
  2. /*
  3.  *  DIO.C
  4.  *
  5.  *  (C)Copyright 1987 by Matthew Dillon, All rights reserved
  6.  *  Freely distributable.  Donations Welcome.  This is NOT shareware,
  7.  *  This is NOT public domain.
  8.  *
  9.  *    Matthew Dillon
  10.  *    891 Regal Rd.
  11.  *    Berkeley, Ca. 94708
  12.  *
  13.  *  EXEC device driver IO support routines... makes everything easy.
  14.  *
  15.  *  dfd = dio_open(name, unit, flags, req/NULL)
  16.  *
  17.  *    open an IO device.  Note: in some cases you might have to provide
  18.  *    a request structure with some fields initialized (example, the
  19.  *    console device requires certain fields to be initialized).  For
  20.  *    instance, if openning the SERIAL.DEVICE, you would want to give
  21.  *    an IOExtSer structure which is completely blank execept for the
  22.  *    io_SerFlags field.
  23.  *
  24.  *    The request structure's message and reply ports need not be
  25.  *    initialized.  The request structure is no longer needed after
  26.  *    the dio_open().
  27.  *
  28.  *    NULL = error, else descriptor (a pointer) returned.
  29.  *
  30.  *
  31.  *  dio_close(dfd)
  32.  *
  33.  *    close an IO device.  Any pending asyncronous requests are
  34.  *    AbortIO()'d and then Wait'ed on for completion.
  35.  *
  36.  *
  37.  *  dio_closegrp(dfd)
  38.  *
  39.  *    close EVERY DIO DESCRIPTOR ASSOCIATED WITH THE dio_open() call
  40.  *    that was the parent for this descriptor.  That is, you can get
  41.  *    a descriptor using dio_open(), dio_dup() it a couple of times,
  42.  *    then use dio_closegrp() on any ONE of the resulting descriptors
  43.  *    to close ALL of them.
  44.  *
  45.  *
  46.  *  dio_ddl(dfd,bool)
  47.  *
  48.  *    Disable BUF and LEN fields in dio_ctl[_to].. dummy parameters
  49.  *    must still be passed, but they are not loaded into the io_Data
  50.  *    and io_Length fields of the io request.  This is for devices
  51.  *    like the AUDIO.DEVICE which has io_Data/io_Length in non-standard
  52.  *    places.
  53.  *
  54.  *  dio_cact(dfd,bool)
  55.  *
  56.  *    If an error occurs (io_Error field), the io_Actual field is usually
  57.  *    not modified by the device driver, and thus contains garbage.  To
  58.  *    provide a cleaner interface, you can have DIO_CTL() and DIO_CTL_TO()
  59.  *    calls automatically pre-clear this field so if an io_Error does
  60.  *    occur, the field is a definate 0 instead of garbage.
  61.  *
  62.  *    In most cases you will want to do this.  An exception is the
  63.  *    TIMER.DEVICE, which uses the io_Actual field for part of the
  64.  *    timeout structure.
  65.  *
  66.  *    This flags the particular dio descriptor to do the pre-clear, and
  67.  *    any new descriptors obtained by DIO_DUP()ing this one will also
  68.  *    have the pre-clear flag set.
  69.  *
  70.  *
  71.  *  dio_dup(dfd)
  72.  *
  73.  *    Returns a new channel descriptor referencing the same device.
  74.  *    The new descriptor has it's own signal and IO request structure.
  75.  *    For instance, if you openned the serial device, you might want
  76.  *    to dup the descriptor so you can use one channel to pend an
  77.  *    asyncronous read, and the other channel to write out to the device
  78.  *    and do other things without disturbing the asyncronous read.
  79.  *
  80.  *
  81.  *  sig = dio_signal(dfd)
  82.  *
  83.  *    get the signal number (0..31) used for a DIO descriptor.
  84.  *    This allows you to Wait() for asyncronous requests.  Note that
  85.  *    if your Wait() returns, you should double check using dio_isdone()
  86.  *
  87.  *      dio_flags(dfd, or, ~and)
  88.  *
  89.  *    Modify the io_Flags field in the request, ORing it with the OR
  90.  *    mask, and ANDing it with ~AND mask.  E.G., the AUDIO.DEVICE requires
  91.  *    some flags be put in io_Flags.
  92.  *
  93.  *  req = dio_ctl_to(dfd, command, buf, len, to)
  94.  *
  95.  *    Same as DIO_CTL() below, but (A) is always syncronous, and
  96.  *    (B) will attempt to AbortIO()+WaitIO() the request if the
  97.  *    timeout occurs before the IO completes.
  98.  *
  99.  *    the 'to' argument is in microseconds.
  100.  *
  101.  *    If timeout occurs before request completes, and DIO aborts the
  102.  *    request, some devices do not have the io_Actual field set
  103.  *    properly.
  104.  *
  105.  *  req = dio_ctl(dfd, command, buf, len)
  106.  *
  107.  *    DIO_CTL() is the basis for the entire library.    It works as follows:
  108.  *
  109.  *    (1) If the channel isn't clear (there is an asyncronous IO request
  110.  *        still pending), DIO_CTL() waits for it to complete
  111.  *
  112.  *    (2) If the command is 0, simply return a pointer to the io
  113.  *        request structure.
  114.  *
  115.  *    (3) If the DIO_CACT() flag is TRUE, the io_Actual field of the
  116.  *        request is cleared.
  117.  *
  118.  *    (4) Set the io_Data field to 'buf', and io_Length field to 'len'
  119.  *        If the command is positive, use DoIO().  If the command
  120.  *        negative, take it's absolute value and then do a SendIO().
  121.  *        (The command is placed in the io_Command field, of course).
  122.  *
  123.  *    (5) return the IO request structure
  124.  *
  125.  *
  126.  *  bool= dio_isdone(dfd)
  127.  *
  128.  *    return 1 if current channel is clear (done processing), else 0.
  129.  *    e.g. if you did, say, an asyncronous read, and dio_isdone() returns
  130.  *    true, you can now use the data buffer returned and look at the
  131.  *    io_Actual field.
  132.  *
  133.  *    You need not do a dio_wait() after dio_isdone() returns 1.
  134.  *
  135.  *
  136.  *  req = dio_wait(dfd)
  137.  *
  138.  *    Wait on the current channel for the request to complete and
  139.  *    then return the request structure. (nop if channel is clear)
  140.  *
  141.  *
  142.  *  req = dio_abort(dfd)
  143.  *
  144.  *    Abort the request on the current channel (nop if channel is
  145.  *    clear).  Sends an AbortIO() if the channel is active and then
  146.  *    WaitIO()'s the request.
  147.  *
  148.  *
  149.  *  MACROS: SEE DIO.H
  150.  *
  151.  */
  152.  
  153. #include <exec/types.h>
  154. #include <exec/io.h>
  155. #include <exec/memory.h>
  156. #include <exec/ports.h>
  157. #include <devices/timer.h>
  158. #include "xmisc.h"
  159.  
  160. #define MPC        (MEMF_CLEAR|MEMF_PUBLIC)
  161. #define CPORT        ior.ior.io_Message.mn_ReplyPort
  162. #define MAXREQSIZE  128     /* big enough to hold all Amiga iorequests */
  163.  
  164. typedef struct IORequest IOR;
  165. typedef struct IOStdReq  STD;
  166. typedef struct MsgPort     PORT;
  167.  
  168. typedef struct {
  169.     STD ior;
  170.     char filler[MAXREQSIZE-sizeof(STD)];
  171. } MAXIOR;
  172.  
  173. typedef struct {
  174.     struct _CHAN *list;
  175.     short refs;
  176. } DIO;
  177.  
  178. typedef struct _CHAN {
  179.     MAXIOR  ior;
  180.     DIO     *base;
  181.     XLIST   link;    /* doubly linked list */
  182.     STD     timer;
  183.     char    notclear;
  184.     char    cact;    /* automatic io_Actual field clear  */
  185.     char    ddl;
  186.     UBYTE   flagmask;
  187. } CHAN;
  188.  
  189. extern CHAN *dio_ctl(), *dio_ctl_to(), *dio_wait(), *dio_abort();
  190. extern PORT *CreatePort();
  191. extern char *AllocMem();
  192.  
  193. CHAN *
  194. dio_open(name, unit, flags, req)
  195. char *name;
  196. MAXIOR *req;     /* not really this big  */
  197. {
  198.     register CHAN *chan;
  199.     register DIO *dio;
  200.     register PORT *port;
  201.     int ret;
  202.  
  203.     dio = (DIO *)AllocMem(sizeof(DIO), MPC);    if (!dio)   goto fail3;
  204.     chan= (CHAN *)AllocMem(sizeof(CHAN), MPC);    if (!chan)   goto fail2;
  205.     if (req)
  206.     chan->ior = *req;
  207.     chan->CPORT = CreatePort(NULL,0);        if (!chan->CPORT) goto fail1;
  208.     chan->ior.ior.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  209.     chan->base = dio;
  210.     chan->flagmask = 0xF0;
  211.     dio->refs = 1;
  212.     if (OpenDevice(name, unit, &chan->ior, flags)) {
  213.     DeletePort(chan->CPORT);
  214. fail1:    FreeMem(chan, sizeof(CHAN));
  215. fail2:    FreeMem(dio, sizeof(DIO));
  216. fail3:    return(NULL);
  217.     }
  218.     llink(&dio->list, &chan->link);
  219.     chan->ior.ior.io_Flags = 0;
  220.     return(chan);
  221. }
  222.  
  223. void
  224. dio_dfm(chan,mask)
  225. CHAN *chan;
  226. {
  227.     chan->flagmask = mask;
  228. }
  229.  
  230. void
  231. dio_ddl(chan,n)
  232. CHAN *chan;
  233. {
  234.     chan->ddl = n;
  235. }
  236.  
  237. void
  238. dio_cact(chan,n)
  239. CHAN *chan;
  240. {
  241.     chan->cact = n;
  242. }
  243.  
  244. void
  245. dio_close(chan)
  246. register CHAN *chan;
  247. {
  248.     dio_abort(chan);
  249.     lunlink(&chan->link);
  250.     if (--chan->base->refs == 0) {
  251.     FreeMem(chan->base, sizeof(DIO));
  252.     CloseDevice(&chan->ior);
  253.     }
  254.     if (chan->timer.io_Message.mn_ReplyPort)
  255.     CloseDevice(&chan->timer);
  256.     DeletePort(chan->CPORT);
  257.     FreeMem(chan, sizeof(CHAN));
  258. }
  259.  
  260. void
  261. dio_closegroup(chan)
  262. register CHAN *chan;
  263. {
  264.     register CHAN *nextc;
  265.  
  266.     for (chan = chan->base->list; chan; chan = nextc) {
  267.     chan = (CHAN *)((char *)chan - ((char *)&chan->link - (char *)chan));
  268.     nextc = (CHAN *)chan->link.next;
  269.     dio_close(chan);
  270.     }
  271. }
  272.  
  273.  
  274. CHAN *
  275. dio_dup(chan)
  276. register CHAN *chan;
  277. {
  278.     register CHAN *nc;
  279.  
  280.     if (chan) {
  281.     nc = (CHAN *)AllocMem(sizeof(CHAN), MPC);   if (!nc) goto fail2;
  282.     nc->ior = chan->ior;
  283.     nc->base = chan->base;
  284.     nc->CPORT = CreatePort(NULL,0);     if (!nc->CPORT) goto fail1;
  285.     nc->ior.ior.io_Flags = NULL;
  286.     nc->cact = chan->cact;
  287.     nc->ddl = chan->ddl;
  288.     nc->flagmask = chan->flagmask;
  289.     ++nc->base->refs;
  290.     llink(&nc->base->list, &nc->link);
  291.     return(nc);
  292. fail1:    FreeMem(nc, sizeof(CHAN));
  293.     }
  294. fail2:
  295.     return(NULL);
  296. }
  297.  
  298. dio_signal(chan)
  299. CHAN *chan;
  300. {
  301.     return(chan->CPORT->mp_SigBit);
  302. }
  303.  
  304. dio_flags(chan,or,and)
  305. long chan;
  306. {
  307.     IOR *ior = (void *)chan;
  308.  
  309.     ior->io_Flags = (ior->io_Flags | or) & ~and;
  310. }
  311.  
  312.  
  313. CHAN *
  314. dio_ctl_to(chan, com, buf, len, to)
  315. register CHAN *chan;
  316. char *buf;
  317. {
  318.     register long mask;
  319.  
  320.     if (chan->timer.io_Message.mn_ReplyPort == NULL) {
  321.     chan->timer.io_Message.mn_ReplyPort = chan->CPORT;
  322.     chan->timer.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  323.     if (OpenDevice("timer.device", UNIT_VBLANK, &chan->timer, 0)) {
  324.         puts("Panic: DIO_CTL_TO: No timer.device");
  325.     }
  326.     chan->timer.io_Command = TR_ADDREQUEST;
  327.     }
  328.     mask = 1 << chan->CPORT->mp_SigBit;
  329.     dio_ctl(chan, (com>0)?-com:com, buf, len);    /* SendIO the request */
  330.     chan->timer.io_Actual = to / 1000000;
  331.     chan->timer.io_Length = to % 1000000;    /* setup timer          */
  332.     chan->timer.io_Flags = 0;
  333.     BeginIO(&chan->timer);        /* start timer running  */
  334.     while (Wait(mask)) {        /* Wait for something   */
  335.     if (CheckIO(chan))        /* request done        */
  336.         break;
  337.     if (CheckIO(&chan->timer)) {    /* timeout?          */
  338.         dio_abort(chan);
  339.         break;
  340.     }
  341.     }
  342.     AbortIO(&chan->timer);        /*    kill the timer    */
  343.     WaitIO(&chan->timer);        /*    remove from rp    */
  344.     return(chan);            /*    return ior  */
  345. }
  346.  
  347.  
  348. CHAN *
  349. dio_ctl(chan, com, buf, len)
  350. register CHAN *chan;
  351. char *buf;
  352. {
  353.     if (chan->notclear) {   /* wait previous req to finish */
  354.     WaitIO(chan);
  355.     chan->notclear = 0;
  356.     }
  357.     if (com) {
  358.     if (chan->cact)
  359.         chan->ior.ior.io_Actual = 0;    /* initialize io_Actual to 0*/
  360.     chan->ior.ior.io_Error = 0;        /* initialize error to 0 */
  361.     if (!chan->ddl) {
  362.         chan->ior.ior.io_Data = (APTR)buf;    /* buffer   */
  363.         chan->ior.ior.io_Length = len;    /* length   */
  364.     }
  365.     if (com < 0) {                /* asyncronous IO  */
  366.         chan->ior.ior.io_Command = -com;
  367.         chan->notclear = 1;
  368.         chan->ior.ior.io_Flags &= chan->flagmask;
  369.         BeginIO(chan);
  370.     } else {                /* syncronous IO  */
  371.         chan->ior.ior.io_Command = com;
  372.         chan->ior.ior.io_Flags = (chan->ior.ior.io_Flags & chan->flagmask) | IOF_QUICK;
  373.         BeginIO(chan);
  374.         if (!(chan->ior.ior.io_Flags & IOF_QUICK))
  375.         WaitIO(chan);
  376.     }
  377.     }
  378.     return(chan);
  379. }
  380.  
  381.  
  382. CHAN *
  383. dio_isdone(chan)
  384. register CHAN *chan;
  385. {
  386.     if (chan->notclear) {    /* if not clear */
  387.     if (CheckIO(chan)) {    /* if done    */
  388.         WaitIO(chan);    /* clear    */
  389.         chan->notclear = 0;
  390.         return(chan);    /* done     */
  391.     }
  392.     return(NULL);        /* notdone    */
  393.     }
  394.     return(chan);        /* done     */
  395. }
  396.  
  397.  
  398. CHAN *
  399. dio_wait(chan)
  400. register CHAN *chan;
  401. {
  402.     if (chan->notclear) {
  403.     WaitIO(chan);        /* wait and remove from rp */
  404.     chan->notclear = 0;
  405.     }
  406.     return(chan);
  407. }
  408.  
  409.  
  410. CHAN *
  411. dio_abort(chan)
  412. register CHAN *chan;
  413. {
  414.     if (chan->notclear) {
  415.     AbortIO(chan);        /* Abort it   */
  416.     WaitIO(chan);        /* wait and remove from rp */
  417.     chan->notclear = 0;
  418.     }
  419.     return(chan);
  420. }
  421.  
  422.  
  423.